----------------Jumpman----------------
A 4am crack                  2016-09-15
---------------------------------------

Name: Jumpman
Genre: arcade
Year: 1983
Author: Randy Glover (Atari version)
Publisher: Epyx
Platform: Apple ][+ or later
Media: double-sided 5.25-inch floppy
OS: custom
Previous cracks: The Woz
Similar cracks:
  #595 Addition Magician
  #476 Microzine 2

Both sides are bootable. I'll start
with side A.

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  read error on T22
  copy displays a graphical title page
    then hangs with the drive motor on

Copy ][+ nibble editor
  T00 -> standard prologues, modified
    epilogues (FF FF FF)
  T01,02 -> not full tracks? looks
    like they have some standard-ish
    sectors, but not 16 per track
    (also corrupted address fields)
  T03,04 -> corrupted address fields
    that claim to be track $00
  T05-T21 -> uncorrupted address fields
    but still non-standard epilogues
  T22 unformatted

When I say "corrupted address fields,"
this is what that looks like:

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 01  START: 21DC  LENGTH: 189D
       ^^

21B8: FF FF FF FF FF FF FF FF   VIEW
21C0: FF FF FF FF FF FF FF FF
21C8: FF FF FF FF FF FF FF FF
21D0: FF FF FF FF FF FF FF FF
21D8: FF FF FF FF FF D5 AA 96  <-21DD
                     ^^^^^^^^
                 address prologue

21E0: AA AA AA AA AA AA AA AA
      ^^^^^ ^^^^^ ^^^^^ ^^^^^
      V000   T00   S00  chksm

21E8: FF FF FF FF FF CF F3 FC
      ^^^^^^^^
  address epilogue

21F0: FF FF D5 AA AD 9B DB B9
            ^^^^^^^^
         data prologue

21F8: B9 DB F2 DE B9 AE B3 BA

---------------------------------------

  A  TO ANALYZE DATA  ESC TO QUIT

  ?  FOR HELP SCREEN  /  CHANGE PARMS

  Q  FOR NEXT TRACK   SPACE TO RE-READ

                 --^--

The disk is lying to me. The address
field claims to be track $00, but it's
really track $01. Bad disk! Stop lying!

Disk Fixer
  ["O" -> "Input/Output Control"]
    set Address Epilogue to "FF FF FF"
    set Data Epilogue to "FF FF FF"
  T00 readable
  T01-T04 unreadable (no option to
    ignore the corrupted address field)
  T05-T21 readable
  T22 unreadable (unformatted)

Copy ][+ sector editor
  ["P" -> "Sector Editor Patcher"]
    set type to "CUSTOM"
    set Address Epilogue to "FF FF"
    set Data Epilogue to "FF FF FF"
  T00 readable
  T05-T21 readable

  ["P" -> "Sector Editor Patcher"]
    set CHECK TRACK to "NO"
  only parts of T01 and T02 readable:
    T01: S03,04,05,06,07,0A,0B,0C,0D,0E
    T02: S01,02,08,09,0F
  T03,04 readable!

Why didn't COPYA work?
  modified epilogue bytes on track $00
  (it never even got to the fun part)

Why didn't Locksmith FDB work?
  ditto

Why didn't my EDD copy work?
  I've seen similar disks, where the
  first N tracks have intentionally
  corrupted address fields. (N varies
  from disk to disk.) There's a custom
  loader that loads the data from those
  corrupted tracks, then transfers
  control to a standard RWTS for the
  rest of the program. Somewhere in the
  corrupted tracks, it will load data
  from consecutive half tracks. (These
  are devilishly difficult to copy, and
  I didn't even try.) That's just an
  educated guess; I could be surprised.

Hey, I can actually validate that guess
in the Copy ][+ nibble editor, which
can read half tracks.

                 --v--

   COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------

TRACK: 01.50  START: 3700  LENGTH: 198E
       ^^^^^

3BD0: FF FF FF FF FF FF FF FF   VIEW
3BD8: FF FF FF FF FF FF FF FF
3BE0: FF FF FF FF FF FF FF FF
3BE8: FF FF C9 FF FF FF FF FF
3BF0: FF FF FF FF FF D5 AA 96  <-3BF5
                     ^^^^^^^^
                  address prologue

3BF8: AA AA AA AA AF AB AF AB
      ^^^^^ ^^^^^ ^^^^^ ^^^^^
      V000   T00   S0B  chksm

3C00: FF FF FF 9F E7 F9 FE FF
      ^^^^^^^^
  address eplogue

3C08: D5 AA AD A7 B4 BD CD ED
      ^^^^^^^^
   data prologue

3C10: ED 9B ED F2 E9 DF B6 AB

---------------------------------------

  A  TO ANALYZE DATA  ESC TO QUIT

  ?  FOR HELP SCREEN  /  CHANGE PARMS

  Q  FOR NEXT TRACK   SPACE TO RE-READ

                 --^--

Jackpot! (Note that it's still claiming
to be track $00, though, just like the
other whole tracks above and below it.)

Next steps:

  1. Trace the boot
  2. ???

                   ~

               Chapter 1
         Boot Trace and Chill


[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0

]CALL -151

*800<2800.28FFM

*801L

; set reset vector
0801-   8A          TXA
0802-   4A          LSR
0803-   4A          LSR
0804-   4A          LSR
0805-   4A          LSR
0806-   09 C0       ORA   #$C0
0808-   85 3F       STA   $3F
080A-   8D F3 03    STA   $03F3
080D-   49 A5       EOR   #$A5
080F-   8D F4 03    STA   $03F4
0812-   A9 00       LDA   #$00
0814-   8D F2 03    STA   $03F2

; hmm
0817-   A9 04       LDA   #$04
0819-   48          PHA

; machine initialization (memory banks,
; TEXT, IN#0, PR#0, &c.)
081A-   8D 81 C0    STA   $C081
081D-   20 2F FB    JSR   $FB2F
0820-   8D 52 C0    STA   $C052
0823-   20 89 FE    JSR   $FE89
0826-   20 93 FE    JSR   $FE93

; clear hi-res screen 1
0829-   A2 20       LDX   #$20
082B-   A0 00       LDY   #$00
082D-   84 06       STY   $06
082F-   A9 20       LDA   #$20
0831-   85 07       STA   $07
0833-   98          TYA
0834-   91 06       STA   ($06),Y
0836-   C8          INY
0837-   D0 FB       BNE   $0834
0839-   E6 07       INC   $07
083B-   CA          DEX
083C-   D0 F6       BNE   $0834

; switch to hi-res screen 1 (blank)
083E-   8D 57 C0    STA   $C057
0841-   8D 50 C0    STA   $C050
0844-   8D 54 C0    STA   $C054
0847-   8D 52 C0    STA   $C052

; set up ($3E) vector to point to the
; sector read routine in the disk
; controller ROM
084A-   A9 5C       LDA   #$5C
084C-   85 3E       STA   $3E

; the disk controller ROM always exits
; via $0801, so set that to an RTS so
; we can JSR and not have to set up a
; loop
084E-   A9 60       LDA   #$60
0850-   8D 01 08    STA   $0801

; hmm
0853-   A9 72       LDA   #$72
0855-   48          PHA

OK, we've now pushed $04/$72 on the
stack. That's probably important.

; multi-sector read
; Y = first logical sector ($01)
; X = last logical sector ($08)
; A = start address high byte ($B8)
0856-   A0 00       LDY   #$00
0858-   84 FC       STY   $FC
085A-   C8          INY
085B-   A9 B8       LDA   #$B8
085D-   A2 08       LDX   #$08

; call multi-sector read routine
085F-   20 6C 08    JSR   $086C

; another sector read, this time just
; one sector, into $AF00 (X is already
; less than Y on entry, so loop will
; exit after one read)
0862-   A9 AF       LDA   #$AF
0864-   A2 01       LDX   #$01
0866-   20 6C 08    JSR   $086C

; final sector read into $0400 (!)
0869-   A9 04       LDA   #$04
086B-   AA          TAX

; falls through to multi-sector read
; entry point (was also called earlier)
086C-   85 27       STA   $27
086E-   E8          INX
086F-   86 49       STX   $49
0871-   84 F9       STY   $F9

; map logical into physical sector and
; store it in zero page where the disk
; controller ROM will look for it
0873-   B9 8A 08    LDA   $088A,Y
0876-   85 3D       STA   $3D

; read sector via disk controller ROM
0878-   20 85 08    JSR   $0885

; loop until done
087B-   A4 F9       LDY   $F9
087D-   C8          INY
087E-   C4 49       CPY   $49
0880-   90 EF       BCC   $0871
0882-   A5 27       LDA   $27
0884-   60          RTS

; subroutine to read a sector via ($3E)
; which points to $Cx5C, which exits
; via $0801, which is now an "RTS"
; (HOW F---ING ELEGANT IS THAT, RIGHT?)
0885-   A6 2B       LDX   $2B
0887-   6C 3E 00    JMP   ($003E)

; physical to logical sector map
088A- .. .. 00 03 05 07 09 0B
0890- 0D 0F 02 04 06 08 0A 0C
0898- 0E 01

That's it. Flexible but compact.

It's a weird combination of reads,
though. It loads a bunch of sectors at
$B800, one at $AF00, then the last one
at $0400. That's part of the text page,
but it's hidden during boot because we
cleared the entire hi-res graphics page
and showed that instead.

Of course, we manually pushed $04/$72
on the stack earlier, so once we fall
through to the sector read routine,
reads the last sector, and hits the RTS
we put at $0801, it will "return" to
$0472 + 1 = $0473.

Let's interrupt the boot before it gets
there.

                   ~

               Chapter 2
 In Which Things Get Brilliantly Weird


*9600<C600.C6FFM

; set up callback by changing the two
; bytes that are pushed to the stack
96F8-   A9 97       LDA   #$97
96FA-   8D 18 08    STA   $0818
96FD-   A9 04       LDA   #$04
96FF-   8D 54 08    STA   $0854

; start the boot
9702-   4C 01 08    JMP   $0801

; callback is here --
; copy $0400 up to higher memory so it
; survives a reboot
9705-   A0 00       LDY   #$00
9707-   B9 00 04    LDA   $0400,Y
970A-   99 00 24    STA   $2400,Y
970D-   C8          INY
970E-   D0 F7       BNE   $9707

; turn off slot 6 drive motor
9710-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9713-   4C 00 C5    JMP   $C500

*BSAVE TRACE,A$9600,L$116

*BRUN TRACE
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.0400-04FF,A$2400,L$100
]CALL -151

The entry point was $0473, so let's
start there. I'll have to leave the
code at $2400. Relative branches will
look correct, but absolute addresses
in $04xx will be +$2000.

*2473L

; zp$4A is important later (see below)
2473-   46 4A       LSR   $4A
2475-   20 9F 04    JSR   $049F

*249FL

249F-   20 33 04    JSR   $0433

*2433L

; call the following line (then fall
; through and do it again)
2433-   20 36 04    JSR   $0436

; save A and Y
2436-   48          PHA
2437-   98          TYA
2438-   48          PHA

; low-level disk stuff (see below)
2439-   A5 FC       LDA   $FC
243B-   85 FD       STA   $FD
243D-   E6 FC       INC   $FC
243F-   A5 FC       LDA   $FC
2441-   29 03       AND   #$03
2443-   0A          ASL
2444-   05 2B       ORA   $2B
2446-   A8          TAY
2447-   B9 81 C0    LDA   $C081,Y

; wait loop
244A-   A9 30       LDA   #$30
244C-   20 A8 FC    JSR   $FCA8

; more low-level disk stuff
244F-   A5 FD       LDA   $FD
2451-   29 03       AND   #$03
2453-   0A          ASL
2454-   05 2B       ORA   $2B
2456-   A8          TAY
2457-   B9 80 C0    LDA   $C080,Y

; more waiting
245A-   A9 30       LDA   #$30
245C-   20 A8 FC    JSR   $FCA8

; restore A and Y on the way out
245F-   68          PLA
2460-   A8          TAY
2461-   68          PLA
2462-   60          RTS

This is a very clever and compact way
to advance the drive head to the next
track. Normally DOS 3.3 keeps track of
this and has a (much more complicated)
routine to move the head back and forth
as needed. But this loader only needs
to move it forward, so the entire
process collapses to this:

1. Set up the Y register to be a slot
   number (x16) plus the appropriate
   phase (0-3, depending on which track
   the drive head is on)

2. LDA $C081,Y to turn on the
   appropriate stepper motor

3. Wait exactly the right amount of
   time (as measured in CPU cycles)

4. LDA $C080,Y to turn off the
   appropriate stepper motor

5. Wait the right amount of time again

...which is exactly what this routine
at $0436 is doing. But that only gets
us halfway there -- literally, it only
moves the drive head by half a track.
But! Since $0433 "falls through" to
$0436, it ends up doing this twice. Two
half tracks equal one whole track, so
calling the routine at $0433 will move
the drive head to the next whole track.

(By the way, this is why it initialized
zero page $FC to $00 at $0858. That's
the "current" track where the drive
head is at boot; it gets updated when
the drive head advances.)

Everything I know about low-level disk
stepping, I learned from this excellent
Usenet post:
macgui.com/usenet/?group=1&id=31160

Continuing from $04A2...

*24A2L

; zero page fiddling (see below)
24A2-   A9 00       LDA   #$00
24A4-   85 41       STA   $41
24A6-   38          SEC
24A7-   66 4A       ROR   $4A

; multi-sector read, similar to the one
; we did in boot0
; Y = first logical sector ($01)
; X = last logical sector ($05)
; A = start address high byte ($A0)
24A9-   A9 A0       LDA   #$A0
24AB-   A0 01       LDY   #$01
24AD-   A2 05       LDX   #$05
24AF-   20 15 04    JSR   $0415

*2415L

; store A in zero page $27, used by the
; disk controller ROM routine as the
; target page to store sectors read
; from disk
2415-   85 27       STA   $27

; X is the final sector to read
2417-   E8          INX
2418-   86 49       STX   $49

; Y is the current sector to read
; (starting with whatever was passed in
; and incrementing until it equals the
; value passed in the X register)
241A-   84 F9       STY   $F9
241C-   98          TYA

; But wait, there's more! Based on the
; high bit of zero page $4A, Y is
; either a logical sector (the map of
; logical->physical sectors is at
; $0463) or a physical sector
241D-   24 4A       BIT   $4A
241F-   30 03       BMI   $2424
2421-   B9 63 04    LDA   $0463,Y

; store physical sector in $3D (again,
; used by the disk controller ROM)
2424-   85 3D       STA   $3D

; read sector by jumping to ($003E),
; which points to $Cx5C (e.g. $C65C if
; booting from slot 6) and exit via
; $0801, which is an RTS by now, so
; this just continues to the next line
2426-   20 00 04    JSR   $0400

; increment sector index
2429-   A4 F9       LDY   $F9
242B-   C8          INY

; are there more sectors to read?
242C-   C4 49       CPY   $49

; yes, branch back and repeat
242E-   90 EA       BCC   $241A

; no, exit with last page (+1) in A
; (disk controller ROM increments this
; after storing sector data, so on exit
; this will be the first page that was
; NOT filled with data in this loop)
2430-   A5 27       LDA   $27
2432-   60          RTS

But wait, it gets even better.

                   ~

               Chapter 3
         Every Byte Is Sacred,
         Every Byte Is Great,
         If A Byte Gets Wasted,
         Woz Gets Quite Irate


Continuing from $04B2...

; move the drive head one phase only,
; to the next HALF track
24B2-   20 36 04    JSR   $0436

[now on track 1.5]

; read more sectors ($06..$0A)
24B5-   A2 0A       LDX   #$0A
24B7-   20 15 04    JSR   $0415

; advance another half track
24BA-   20 36 04    JSR   $0436

[now on track 2]

; read more sectors ($0B..$0F)
24BD-   A2 0F       LDX   #$0F
24BF-   20 15 04    JSR   $0415

; fiddle with $4A again
24C2-   46 4A       LSR   $4A
24C4-   60          RTS

So here's the deal with $4A: we
initialized it at $0473 by a blind LSR,
which clears the high bit. This tells
the multi-sector read routine at $0415
to use logical sectors. Then we set the
high bit at $04A6 with SEC + ROR,
indicating we want $0415 to read
physical sectors. Then we read a few
sectors from track 1, a few from track
1.5, and a few from track 2. Then we
reset $4A with another LSR, and we're
back to using logical sectors.

This explains why my EDD bit copy
failed. This disk is storing data on
half tracks. Worse, it's storing data
on *adjacent* half tracks -- a few from
track 1, a few from track 1.5, and a
few from track 2. Due to limitations of
the Disk II drive mechanism, that would
be virtually impossible for a generic
bit copier to reproduce on a blank
floppy disk.

Every part of this code is brilliant,
AND it fits in a single sector on the
text page, AND it's flexible enough to
read from virtually uncopyable disks.

Continuing from $0478...

*2478L

2478-   A9 80       LDA   #$80
247A-   20 0E 04    JSR   $040E

This is very interesting. $0405 looks
like this:

*2405L

2405-   20 0E 04    JSR   $040E
2408-   20 0E 04    JSR   $040E
240B-   20 0E 04    JSR   $040E
240E-   20 33 04    JSR   $0433
2411-   A2 0F       LDX   #$0F
2413-   A0 00       LDY   #$00
2415-   85 27       STA   $27
.
. multi-sector read routine (see above)
.

$0411 sets X and Y to read an entire
track (sector $00 through $0F). Before
that, $040E advances to the next whole
track. And before *that*, we have three
identical JSRs to $040E, each of which
falls through to the next, and
eventually to $040E again.

Thus, calling $040E will advance one
whole track and read one whole track.
Calling $040B will do that twice,
reading each track into consecutive
memory (because the multi-sector read
routine ends with next page in memory
in the accumulator, so you can chain
them and just fill up memory without
having to reset the starting page).

Calling $0408 will do it three times,
and calling $0405 will do it four times
(again, into consecutive memory). So
these two lines of code...

2478-   A9 80       LDA   #$80
247A-   20 0E 04    JSR   $040E

...will advance to track $03 and read
it into $8000..$8FFF.

Continuing from $047D...

; advance one whole track
247D-   20 33 04    JSR   $0433

[now on track 4]

; read most of track 4 into the next
; consecutive address after the last
; read, so $9000+
2480-   A2 0C       LDX   #$0C
2482-   20 13 04    JSR   $0413

By hook and by crook, we've managed to
fill up $B800..$BFFF (from track 0) and
most of $8000..$AFFF (from tracks 1,
1.5, 2, 3, and 4 -- oh, and one sector
from track 0 just for good measure).

; turn off drive motor
2485-   A6 2B       LDX   $2B
2487-   BD 88 C0    LDA   $C088,X

; set up DOS globals (tracking where
; the drive head is)
248A-   20 8E BE    JSR   $BE8E
248D-   A5 FC       LDA   $FC
248F-   99 78 04    STA   $0478,Y
2492-   4A          LSR
2493-   8D 78 04    STA   $0478

; push $7F/$FF to the stack
2496-   A9 7F       LDA   #$7F
2498-   48          PHA
2499-   A9 FF       LDA   #$FF
249B-   48          PHA

; and exit via HOME routine
249C-   4C 58 FC    JMP   $FC58

And that's where I get to interrupt the
boot.

                   ~

               Chapter 4
       In Which We See The Light
       At The End Of The Tunnel,
       And It's A DOS-shaped RWTS
       Which Is A Weird Thing To
       See In A Tunnel, Honestly


*9600<C600.C6FFM

; set up callback #1 and start the boot
96F8-   A9 97       LDA   #$97
96FA-   8D 18 08    STA   $0818
96FD-   A9 04       LDA   #$04
96FF-   8D 54 08    STA   $0854
9702-   4C 01 08    JMP   $0801

; callback #1 is here --
; set up an unconditional break to the
; monitor ($FF59) after we load tracks
; 1, 1.5, 2, 3, and 4 into memory
9705-   A9 4C       LDA   #$4C
9707-   8D 9C 04    STA   $049C
970A-   A9 59       LDA   #$59
970C-   8D 9D 04    STA   $049D
970F-   A9 FF       LDA   #$FF
9711-   8D 9E 04    STA   $049E

; continue the boot
9714-   4C 73 04    JMP   $0473

*BSAVE TRACE2,A$9600,L$117

; fill memory with an unusual byte (to
; more easily spot pages that were
; modified during boot)
*800:FD N 801<800.BEFEM
*BRUN TRACE2
...reboots slot 6...
...read read read...
<beep>

Some manual listing confirms that we
have successfully captured $8000..$AFFF
and $B800..$BFFF in memory. The part at
$B800 is a DOS 3.3-shaped RWTS, likely
used to read the rest of the disk after
the custom bootloader zaps itself from
memory by calling HOME (which wipes the
text screen).

; copy used portions to lower memory so
; they survive a reboot
*2000<8000.AFFFM
*5800<B800.BFFFM

; reboot to my work disk
*C500G
...

; save the captured memory chunks
]BSAVE OBJ.8000-AFFF,A$2000,L$3000
]BSAVE RWTS,A$5800,L$800
]CALL -151

*5800L
.
. appears to be a DOS-shaped RWTS
.
5898-   A6 27       LDX   $27
589A-   20 BB B8    JSR   $B8BB
589D-   A9 FF       LDA   #$FF
589F-   20 B8 B8    JSR   $B8B8
58A2-   A9 FF       LDA   #$FF
58A4-   20 B8 B8    JSR   $B8B8
58A7-   A9 EB       LDA   #$EB
...

Confirmed: after the bootloader exits,
we have a full DOS 3.3 RWTS in memory.
Spot checking the RWTS, it's perfectly
normal except it expects "FF FF FF"
epilogue bytes. Which, by the way, is
just the sort of RWTS that could read
tracks $05-$21.

                   ~

               Chapter 5
     In Which Everything Is Simple
    If You Look At It The Right Way


Using Super Demuffin (with epilogues
"FF FF FF"), I "copied" the original
disk to a freshly formatted blank
disk. Of course, this only got track
$00 and tracks $05-$21, but I'll take
it.

                 --v--

     LOCKSMITH 7.0  FAST DISK BACKUP


   R.****.............................*
   W***********************************
HEX 00000000000000001111111111111111222
TRK 0123456789ABCDEF0123456789ABCDEF012
   0.AAAA.............................A
   1.AAAA.............................A
   2.AAAA.............................A
   3.AAAA.............................A
   4.AAAA.............................A
   5.AAAA.............................A
   6.AAAA.............................A
   7.AAAA.............................A
   8.AAAA.............................A
   9.AAAA.............................A
   A.AAAA.............................A
   B.AAAA.............................A
   C.AAAA.............................A
   D.AAAA.............................A
12 E.AAAA.............................A
   F.AAAA.............................A
[               ] PRESS [RESET] TO EXIT

                 --^--

Now I need to write everything that I
captured from the corrupted tracks back
to tracks $01-$04.

Disk layout comparison:

track | old address | new address
------+-------------+-------------
 $01  | $A000-$A4FF | $8000-$8FFF
$01.5 | $A500-$A9FF |
 $02  | $AA00-$AEFF | $9000-$9FFF
 $03  | $8000-$8FFF | $A000-$AFFF
 $04  | $9000-$9CFF |

Of course, all the tracks will now have
normal address fields (no more lying
about the track numbers). Also no half
tracks and no spirals. Just, you know,
sectors on a disk. All the spiral track
stuff collapses into a single track, so
track $04 is completely unused.

[S6,D1=demuffin'd copy (T00, T05-T21)]
[S5,D1=my work disk]

]PR#5
...
]CALL -151

*300L

; page count (decremented)
0300-   A9 30       LDA   #$30
0302-   85 FF       STA   $FF

; logical sector (incremented)
0304-   A9 00       LDA   #$00
0306-   85 FE       STA   $FE

; call RWTS to write sector
0308-   A9 03       LDA   #$03
030A-   A0 88       LDY   #$88
030C-   20 D9 03    JSR   $03D9

; increment logical sector, wrap around
; from $0F to $00 and increment track
030F-   E6 FE       INC   $FE
0311-   A4 FE       LDY   $FE
0313-   C0 10       CPY   #$10
0315-   D0 07       BNE   $031E
0317-   A0 00       LDY   #$00
0319-   84 FE       STY   $FE
031B-   EE 8C 03    INC   $038C

; Convert to the interleave order that
; this disk expects
031E-   B9 40 03    LDA   $0340,Y
0321-   8D 8D 03    STA   $038D

; increment page to write
0324-   EE 91 03    INC   $0391
0327-   C6 FF       DEC   $FF

; loop until done with all pages
0329-   D0 DD       BNE   $0308
032B-   60          RTS

; sector interleave table
*340.34F

0340- 00 06 05 04 03 02 01 0F
0348- 0E 0D 0C 0B 0A 09 08 07

; RWTS parameter table, pre-initialized
; with slot 6, drive 1, track $01,
; sector $00, address $2000, and RWTS
; write command ($02)
*388.397

0388- 01 60 01 00 01 00 FB F7
0390- 00 20 00 00 02 00 00 60

*BSAVE MAKE,A$300,L$98
*BLOAD OBJ.8000-AFFF,A$2000
*300G
...write write write...

Now I need to modify the bootloader at
$0473 slightly.

  1. Modify the routine at $0433 (that
     advances the drive head) so it
     updates zero page $41 with the
     current track.

  2. Modify the routine at $0473 so it
     reads $8000-$AFFF from tracks 1-3.
     No tricks, no traps.

The sector read routine at $C65C
compares the track listed in the
address field to zero page $41 and
loops forever until it matches. $C600
initializes $41 to 0, and the original
disk never updates $41, but everything
works because the address fields are
corrupted and all claim to be track 0.

So part of it will be simpler, because
we'll no longer be spiraling between
tracks. But part of it will actually
be more complicated because the address
fields are no longer corrupted and we
need to track the track number.

First, a patch at $0473 to load tracks
1-3 directly into $8000-$AFFF. We can
reuse the existing code at $0408 (which
falls through to $040B (which falls
through to $040E (which calls $0433 and
falls through to $0411))).

T00,S0C,$73 -> A9 80 20 08 04 4C 85 04

which looks like this (using Disk
Fixer's built-in disassembler):

                 --v--

0073:A9 80          LDA   #$80
0075:20 08 04       JSR   $0408
0078:4C 85 04       JMP   $0485

                 --^--

Second, a new routine at $047B (now
unused space) to increment the track
number in zero page.

T00,S0C,$7B -> E6 41 4C 36 04

                 --v--

007B:E6 41          INC   $41
007D:4C 36 04       JMP   $0436

                 --^--

Third, the patch at $0433 to call the
new routine at $047B so we increment
the track number in zero page before
advancing the drive arm.

T00,S0C,$34: 36 -> 7B

                 --v--

0033:20 7B 04       JSR   $047B

                 --^--

And finally, several patches to the DOS
3.3-shaped RWTS that was loaded from
track 0 and later used to read the rest
of the disk (T05+). The sector ordering
is weird because it's loading them in
physical sector order, but I found all
the usual patch points.

T00,S02,$AE: FF -> DE
T00,S02,$B3: FF -> AA
T00,S05,$35: FF -> DE
T00,S05,$3F: FF -> AA
T00,S05,$91: FF -> DE
T00,S05,$9B: FF -> AA
T00,S06,$9E: FF -> DE
T00,S06,$AE: FF -> AA

]PR#6
...works, and it is glorious...

Side B has identical protection.

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 840
------------------EOF------------------
